/**
 * @Title: CodeGenerator
 * @Package cn.com.artemis.biz.steinsggs.common.util
 * @Description: TODO
 * @author yulin.xu@downjoy.com
 * @date 2017/7/19 15:23
 * @version V1.0
 */
package cn.com.artemis.biz.steinsggs.common.util;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;

import java.io.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 *@ClassName: CodeGenerator
 * @Description: TODO
 * @author yulin.xu@downjoy.com
 * @date 2017/7/19 15:23
 *
 */
public class CodeGenerator {

    private String outPath = "D://codeGenerator";
    private String templatePath = "/template";
    private static String url = "jdbc:mysql://101.201.68.143:3306/heavy_metal?useUnicode=true&characterEncoding=utf-8&characterSetResults=utf-8&zeroDateTimeBehavior=round";
//    private static String url = "jdbc:mysql://192.168.9.63:3306/fx_sdk?useUnicode=true&characterEncoding=utf-8&characterSetResults=utf-8&zeroDateTimeBehavior=round";
    private static String username = "root" ;
//    private static String username = "dml_fx_sdk" ;
    private static String password = "ni4bu4sha" ;
//    private static String password = "T3O~f+I4xan6o[uK" ;
    private static String dbName = "heavy_metal";
//    private static String dbName = "fx_sdk";
    private String toPackPath = "cn.com.artemis.biz.steinsggs.to";
    private String mapperPackPath = "cn.com.artemis.biz.steinsggs.dao";
    private String queryToPackPath = "cn.com.artemis.biz.steinsggs.queryto";

    private Configuration cfg;
    private Connection con;
    private List<Map<String, Object>> tables;

    private void init() {
        tables = new ArrayList<Map<String, Object>>();
        cfg = new Configuration(Configuration.VERSION_2_3_25);
        cfg.setClassForTemplateLoading(CodeGenerator.class, templatePath);
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        cfg.setLogTemplateExceptions(false);
        try {
            con = DriverManager.getConnection(url , username , password );
            getTables();
            getTableInfo();
            checkDir();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public CodeGenerator() {
        init();
    }

    private ResultSet runSql(String sql) {
        Statement stmt = null;
        try {
            stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery(sql) ;
            return rs;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void getTables() {
        ResultSet rs = runSql(String.format("select table_name from information_schema.tables where table_schema='%s'", dbName));
        if (null != rs) {
            try {
                while(rs.next()){
                    String tableName = rs.getString(1) ;
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put("name", tableName);
                    map.put("nameAlias", tableName.substring(0, 1));
                    map.put("toPackPath", toPackPath);
                    map.put("mapperPackPath", mapperPackPath);
                    map.put("queryToPackPath", queryToPackPath);
                    tables.add(map);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    private void toFieldHandle(String name, String type, Map<String, String> fieldMap, Map<String, Object> table) {
        if ("int".equals(type) || "tinyint".equals(type)) {
            fieldMap.put("type", "Integer");
            fieldMap.put("mapper_type", "INTEGER");
        }
        if ("varchar".equals(type) || "char".equals(type)) {
            fieldMap.put("type", "String");
            fieldMap.put("mapper_type", "VARCHAR");
        }
        if ("datetime".equals(type) || "date".equals(type)) {
            fieldMap.put("type", "Date");
            fieldMap.put("mapper_type", "TIMESTAMP");
            table.put("hasDate", true);
        }
        if ("decimal".equals(type)) {
            fieldMap.put("type", "BigDecimal");
            fieldMap.put("mapper_type", "DECIMAL");
            table.put("hasBigDecimal", true);
        }
        String toName = name;
        if (name.startsWith("pk")) {
            toName = name.replace("pk_", "");
        }
        toName = StringUtils.underlineToCamel(toName);
        fieldMap.put("toName", toName);
        String camelName = StringUtils.underlineToCamel(toName);
        fieldMap.put("name", name);
        fieldMap.put("captureName", StringUtils.captureName(camelName));
    }

    private void getTableInfo() {
        ResultSet rs;
        for (Map<String, Object> table:
             tables) {
            String tableName = (String) table.get("name");
            table.put("tableName", tableName);
            String name = tableName.toLowerCase();
            table.put("name", name);
            table.put("captureName", StringUtils.captureName(StringUtils.underlineToCamel(name)));
            rs = runSql(String.format("select column_name, data_type, column_comment, column_key from information_schema.columns where table_schema='%s' and table_name='%s'", dbName, tableName));
            List<Map<String, String>> list = new ArrayList<Map<String, String>>();
            table.put("fields", list);
            if (null != rs) {
                try {
                    while(rs.next()){
                        String column_name = rs.getString(1);
                        String data_type = rs.getString(2);
                        String column_comment = rs.getString(3);
                        String column_key = rs.getString(4);
                        Map<String, String> field = new HashMap<String, String>();
                        toFieldHandle(column_name, data_type, field, table);
                        field.put("comment", column_comment);
                        field.put("key", column_key);
                        if (org.apache.commons.lang3.StringUtils.isNotEmpty(column_key)) {
                            table.put("pkName", column_name);
                            table.put("pk_mapper_type", field.get("mapper_type"));
                            String pkToName = field.get("toName");
                            table.put("pkToName", pkToName);
                        }
                        list.add(field);
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void checkDir() {
        File dir = new File(outPath);
        if (!dir.exists()) {
            dir.mkdir();
        }
        dir = new File(outPath + "//to");
        if (!dir.exists()) {
            dir.mkdir();
        }
        dir = new File(outPath + "//dao");
        if (!dir.exists()) {
            dir.mkdir();
        }
        dir = new File(outPath + "//mapper");
        if (!dir.exists()) {
            dir.mkdir();
        }
        dir = new File(outPath + "//html");
        if (!dir.exists()) {
            dir.mkdir();
        }
    }

    private void run(String ftlName, String dir, String outFileName) {
        try {
            Template temp = cfg.getTemplate(ftlName);
            for (Map<String, Object> table:
                    tables) {
                String tableName = (String) table.get("captureName");
                File file = new File(outPath + "//" + dir + "//" + tableName + outFileName);
                if (!file.exists()) {
                    file.createNewFile();
                }
                FileOutputStream fos = new FileOutputStream(file);
                Writer out = new OutputStreamWriter(fos);
                try {
                    temp.process(table, out);
                    fos.close();
                } catch (TemplateException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void generateDao() {
        run("dao.javaftl", "dao","Mapper.java");
    }

    private void generateTO() {
        run("to.javaftl", "to","TO.java");
    }

    private void generateMapper() {
        run("mapper.mapperftl", "mapper","Mapper.xml");
    }

    private void generateHtml() {
        run("html.htmlftl", "html",".html");
    }

    public static void main(String[] args) {

        CodeGenerator codeGenerator = new CodeGenerator();
        codeGenerator.generateDao();
        codeGenerator.generateTO();
        codeGenerator.generateMapper();
        codeGenerator.generateHtml();

    }

}
